using UnityEngine;

public class NetCollisionHandler : CollisionHandlerBase
{
	public struct QuadraticRoots
	{
		public float rootSmall;

		public float rootLarge;
	}

	private static NetCollisionHandler _instance;

	public static NetCollisionHandler instance
	{
		get
		{
			if (_instance == null)
			{
				_instance = new NetCollisionHandler();
			}
			return _instance;
		}
	}

	public override CollisionBallParams MotionParamsAfterCollision(CollisionBallParams initialParams, float mass, float radius)
	{
		CollisionBallParams result = default(CollisionBallParams);
		result.position = initialParams.position;
		result.optionalNormal = GetNormalToCollision(initialParams, radius);
		result.velocity = initialParams.velocity + GetVelocityFromBounce(initialParams, mass, radius);
		result.angularVelocity = initialParams.angularVelocity * BallFlightConstants.instance.coeffRestitutionNet;
		return result;
	}

	private Vector3 GetPositionAtCollision(CollisionBallParams initialParams, float radius)
	{
		float timeToCollision = GetTimeToCollision(initialParams, radius);
		return initialParams.position - initialParams.velocity * timeToCollision;
	}

	private Vector3 GetVelocityFromBounce(CollisionBallParams initialParams, float mass, float radius)
	{
		Vector3 normalToCollision = GetNormalToCollision(initialParams, radius);
		float impulseForCollision = GetImpulseForCollision(initialParams, normalToCollision, mass);
		return impulseForCollision * normalToCollision / mass;
	}

	private float GetTimeToCollision(CollisionBallParams initialParams, float radius)
	{
		float num = GetTimeAtZPosition(initialParams, Mathf.Abs(initialParams.position.z) - radius);
		float num2 = initialParams.position.y - initialParams.velocity.y * num;
		float num3 = Table.tabletopy + Table.netHeight;
		if (num2 > num3)
		{
			QuadraticRoots timeToRadius = GetTimeToRadius(initialParams, radius, num3);
			float num4 = initialParams.position.y - initialParams.velocity.y * timeToRadius.rootSmall;
			num = ((!(num4 < num3)) ? timeToRadius.rootSmall : timeToRadius.rootLarge);
		}
		return num;
	}

	private Vector3 GetNormalToCollision(CollisionBallParams initialParams, float radius)
	{
		float timeToCollision = GetTimeToCollision(initialParams, radius);
		Vector3 vector = initialParams.position - initialParams.velocity * timeToCollision;
		vector.x = 0f;
		float a = Table.tabletopy + Table.netHeight;
		Vector3 vector2 = new Vector3(0f, Mathf.Min(a, vector.y), 0f);
		float netRotation = GetNetRotation(vector2.y, radius, initialParams.velocity.z);
		return Quaternion.Euler(netRotation, 0f, 0f) * (vector - vector2).normalized;
	}

	private float GetTimeAtZPosition(CollisionBallParams initialParams, float zDist)
	{
		return Mathf.Abs(zDist / initialParams.velocity.z);
	}

	private QuadraticRoots GetTimeToRadius(CollisionBallParams initialParams, float radius, float fixedHeight)
	{
		float num = initialParams.velocity.y * initialParams.velocity.y + initialParams.velocity.z * initialParams.velocity.z;
		float num2 = 2f * initialParams.position.y * initialParams.velocity.y - 2f * initialParams.velocity.y * fixedHeight;
		float num3 = initialParams.position.y * initialParams.position.y + fixedHeight * fixedHeight - 2f * initialParams.position.y * fixedHeight - radius * radius;
		QuadraticRoots result = default(QuadraticRoots);
		result.rootSmall = Mathf.Abs((0f - num2 + Mathf.Sign(num2) * Mathf.Sqrt(num2 * num2 - 4f * num * num3)) / (2f * num));
		result.rootLarge = Mathf.Abs((0f - num2 - Mathf.Sign(num2) * Mathf.Sqrt(num2 * num2 - 4f * num * num3)) / (2f * num));
		return result;
	}

	private float GetNetRotation(float impactHeight, float radius, float velInZ)
	{
		float num = Table.tabletopy + Table.netHeight;
		if (impactHeight >= num + radius)
		{
			return 0f;
		}
		float num2 = Mathf.Abs(impactHeight - num);
		if (impactHeight > num)
		{
			num2 *= BallFlightConstants.instance.maxNetBendingHeightInRadiusMultiples;
		}
		float num3 = 1f - Mathf.Min(1f, num2 / (BallFlightConstants.instance.maxNetBendingHeightInRadiusMultiples * radius));
		float num4 = num3 * BallFlightConstants.instance.netElasticityFactor * velInZ;
		if (Mathf.Abs(num4) > BallFlightConstants.instance.maxNetBendingAngle)
		{
			num4 = Mathf.Sign(num4) * BallFlightConstants.instance.maxNetBendingAngle;
		}
		return num4;
	}

	private float GetImpulseForCollision(CollisionBallParams initialParams, Vector3 collisionNormal, float mass)
	{
		return Mathf.Abs(Vector3.Dot(initialParams.velocity, collisionNormal)) * (BallFlightConstants.instance.coeffRestitutionNet + 1f) / (1f / mass);
	}
}
